/**
 * @name Uploader.js
 * @author Jiang
 * @create	2012-12-20
 * @version 0.1
 * @description	The Annouse funtion for HTML5/FLASH/FORM upload method. The
 * 	function will autoly to choose the property method to ajust to client
 *  Browswer. This js function mainly borrow from youku.com's uploader.min.js
 *  and try to re-create it for fullfiting my requirement.
 * @example
 * 		1. new Stream();
 * 		2. var cfg = {
 * 				extFilters : [".txt", ".gz"],
 * 				fileFieldName : "FileData"
 * 			};
 * 		   new Stream(cfg);
 */
(function(){
  var uploading = 0;
  var Provider, aFilters = [], nIdCount = 0, aOtherBrowsers = ["Maxthon", "SE 2.X", "QQBrowser"],
    nZero = 0, sOneSpace = " ", sLBrace = "{", sRBrace = "}",
    ga = /(~-(\d+)-~)/g, rLBrace = /\{LBRACE\}/g, rRBrace = /\{RBRACE\}/g,
    ea = {
      "&" : "&amp;",
      "<" : "&lt;",
      ">" : "&gt;",
      '"' : "&quot;",
      "'" : "&#x27;",
      "/" : "&#x2F;",
      "`" : "&#x60;"
    }, pa = Array.isArray && /\{\s*\[(?:native code|function)\]\s*\}/i.test(Array.isArray)
      ? Array.isArray
      : function(a) {return "array" === fToString(a)},
    sStreamMessagerId = "i_stream_message_container",
    sCellFileTemplate = '<b class="stream-uploading-ico"></b>' +
      '<div class="stream-file-name"><strong></strong></div>' +
      '<div class="stream-process">' +
      '	<a class="stream-cancel" href="javascript:void(0)">删除</a>' +
      '	<span class="stream-process-bar"><span style="width: 0%;"></span></span>' +
      '	<span class="stream-percent">0%</span>' +
      '</div>' +
      '<div class="stream-cell-infos">' +
      '	<span class="stream-cell-info">速度：<em class="stream-speed"></em></span>' +
      '	<span class="stream-cell-info">已上传：<em class="stream-uploaded"></em></span>' +
      '	<span class="stream-cell-info">剩余时间：<em class="stream-remain-time"></em></span>' +
      '</div>',
    sTotalContainer = '<div id="#totalContainerId#" class="stream-total-tips">' +
      '	上传总进度：<span class="stream-process-bar"><span style="width: 0%;"></span></span>' +
      '	<span class="stream-percent">0%</span>，已上传<strong class="_stream-total-uploaded">&nbsp;</strong>' +
      '	，总文件大小<strong class="_stream-total-size">&nbsp;</strong>' +
      '</div>',
    sFilesContainer	= '<div class="stream-files-scroll" style="height: #filesQueueHeight#px;"><ul id="#filesContainerId#"></ul></div>';

  function fGenerateId(prefix) {
    var b = (new Date).getTime() + "_01v_" + ++nIdCount;
    return prefix ? prefix + "_" + b : b;
  }
  function fGetRandom() {
    return (new Date).getTime().toString().substring(8);
  }
  function fExtend(a, b){
    var c = 2 < arguments.length ? [arguments[2]] : null;
    return function(){
      var d = "string" === typeof a ? b[a] : a,e=c ? [arguments[0]].concat(c) : arguments;
      return d.apply(b||d, e);
    };
  }

  function fAddEventListener(a, b, c) {
    a.addEventListener ? a.addEventListener(b, c, !1) : a.attachEvent ? a
      .attachEvent("on" + b, c) : a["on" + b] = c;
  }

  function fRemoveEventListener(a, b, c) {
    a.removeEventListener ? a.removeEventListener(b, c, !1) : a.detachEvent
      ? a.detachEvent("on" + b, c)
      : a["on" + b] = null;
  }

  function fToString(a) {
    var b = {
      "undefined" : "undefined",
      number : "number",
      "boolean" : "boolean",
      string : "string",
      "[object Function]" : "function",
      "[object RegExp]" : "regexp",
      "[object Array]" : "array",
      "[object Date]" : "date",
      "[object Error]" : "error"
    };
    return b[typeof a] || b[Object.prototype.toString.call(a)] || (a ? "object" : "null");
  }

  function fAddVars(json, url, c) {
    var _array = [], _sep = "&", f = function(json, c) {
      var e = url ? /\[\]$/.test(url) ? url : url + "[" + c + "]" : c;
      "undefined" != e && "undefined" != c
      && _array.push("object" === typeof json
        ? fAddVars(json, e, !0)
        : "[object Function]" === Object.prototype.toString.call(json)
        ? encodeURIComponent(e) + "=" + encodeURIComponent(json())
        : encodeURIComponent(e) + "=" + encodeURIComponent(json))
    };
    if (!c && url)
      _sep = /\?/.test(url) ? /\?$/.test(url) ? "" : "&" : "?",
        _array.push(url),
        _array.push(fAddVars(json));
    else if ("[object Array]" === Object.prototype.toString.call(json)
      && "undefined" != typeof json)
      for (var g = 0, c = json.length; g < c; ++g)
        f(json[g], g);
    else if ("undefined" != typeof json && null !== json && "object" === typeof json)
      for (g in json)
        f(json[g], g);
    else
      _array.push(encodeURIComponent(url) + "=" + encodeURIComponent(json));
    return _array.join(_sep).replace(/^&/, "").replace(/%20/g, "+")
  }

  function fMergeJson(base, extend) {
    var result = {};
    for (var attr in base)
      result[attr] = base[attr];
    for (var attr in extend)
      result[attr] = extend[attr];
    return result;
  }

  function fAddClass(element, klass) {
    fHasClass(element, klass) || (element.className += " " + klass);
  }

  function fHasClass(element, klass) {
    return RegExp("(^| )" + klass + "( |$)").test(element.className);
  }

  function fRemoveClass(element, klass) {
    element.className = element.className.replace(RegExp("(^| )" + klass + "( |$)"), " ")
      .replace(/^\s+|\s+$/g, "");
  }

  function fContains(container, klass) {
    if (!container)
      return [];
    if (container.querySelectorAll)
      return container.querySelectorAll("." + klass);
    for (var c = [], eles = container.getElementsByTagName("*"), e = eles.length, f = 0; f < e; f++)
      fHasClass(eles[f], klass) && c.push(eles[f]);
    return c;
  }

  function fCreateContentEle(content) {
    var b = document.createElement("div");
    b.innerHTML = content;
    content = b.childNodes;
    return content[0].parentNode.removeChild(content[0]);
  }

  function fShowMessage(msg, warning) {
    var o = document.getElementById(sStreamMessagerId);
    o && (o.innerHTML += "<br>" + (!!warning ? ("<span style='color:red;'>" + msg + "</span>"): msg));
  }

  function fMessage(msg, VarVals, c, d) {
    for (var nLIndex, nRIndex, sepIndex, argName, secondVar, s = [], _argName, length = msg.length;;) {
      nLIndex = msg.lastIndexOf(sLBrace, length);
      if (0 > nLIndex)
        break;
      nRIndex = msg.indexOf(sRBrace, nLIndex);
      if (nLIndex + 1 >= nRIndex)
        break;
      argName = _argName = msg.substring(nLIndex + 1, nRIndex);
      secondVar = null;
      sepIndex = argName.indexOf(sOneSpace);
      -1 < sepIndex && (secondVar = argName.substring(sepIndex + 1), argName = argName.substring(0, sepIndex));
      sepIndex = VarVals[argName];
      c && (sepIndex = c(argName, sepIndex, secondVar));
      "undefined" === typeof sepIndex && (sepIndex = "~-" + s.length + "-~", s.push(_argName));
      msg = msg.substring(0, nLIndex) + sepIndex + msg.substring(nRIndex + 1);
      d || (length = nLIndex - 1);
    }
    return msg.replace(ga, function(msg, VarVals, c) {
      return sLBrace + s[parseInt(c, 10)] + sRBrace
    }).replace(rLBrace, sLBrace).replace(rRBrace, sRBrace);
  }

  function fIsObjOrFun(a, b) {
    var c = typeof a;
    return a && ("object" === c || !b && ("function" === c || "function" === fToString(a))) || !1;
  }
  function fIsNumber(val) {
    return "number" === typeof val && isFinite(val);
  }
  function fIsArray(val) {
    return "array" === fToString(val);
  }

  /**
   * This function is for registering the function(s) on its prototype.
   * @hostPrototype	which is its host prototype.
   * @funs	functions, such as{aa:function(){}, bb:function(){}}
   * @forseReg	boolean: when the @hostPrototype don't have the function, then register it.
   * 		true: do it, ignore the @hostPrototype whether has it.
   * 		false: when not have it so that register it.
   */
  function fRegFuns(hostPrototype, funs, forseReg, d) {
    var e, f, g;
    if (!hostPrototype || !funs)
      return hostPrototype || {};
    if (d)
      for (e = 0, g = d.length; e < g; ++e)
        f = d[e], Object.prototype.hasOwnProperty.call(funs, f)	&& (forseReg || !(f in hostPrototype)) && (hostPrototype[f] = funs[f]);
    else {
      for (f in funs)
        Object.prototype.hasOwnProperty.call(funs, f) && (forseReg || !(f in hostPrototype)) && (hostPrototype[f] = funs[f]);
      ({valueOf : 0}).propertyIsEnumerable("valueOf")	|| fRegFuns(hostPrototype, funs, forseReg, "hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toString,toLocaleString,valueOf".split(","));
    }
    return hostPrototype;
  }

  function fRegEvents() {
    fRegFuns(this.constructor.prototype, {
      publish : function(a) {
        this._evts[a] || (this._evts[a] = null);
      },
      on : function(a, b, c) {
        var d = this._evts;
        d[a] = {};
        d[a].type = a;
        this.name && (d[a].type = this.name + ":" + a);
        d[a].fn = function() {
          b.apply(c, arguments);
        };
      },
      after : function(a, b, c) {
        this.on(a, b, c);
      },
      fire : function(a) {
        var b = this._evts[a];
        if (b) {
          var c = {target : this,	type : b.type},
            d = Array.prototype.slice.call(arguments, 1);
          if (fIsObjOrFun(d[0]))
            for (var e in c)
              d[0][e]	? d[0]["_" + e] = c[e] : d[0][e] = c[e];
          else
            d[0] = c;
          "function" === fToString(b.fn) && b.fn.apply(this, d);
        }
      },
      detach : function(a) {
        delete this._evts[a];
      }
    }, !1);
    this._evts = {};
  }


  function Parent(args) {
    fRegEvents.call(this);
    this._isApplySuperClass || fRegFuns(this.constructor.prototype, Parent.prototype, !1);
    if (args) {
      for (var field in args)
        this.set(field, args[field]);
    }
    "function" === typeof this.initializer && this.initializer.apply(this, arguments);
  }
  Parent.prototype = {
    _isApplySuperClass : !0,
    initializer : function() {
    },
    get : function(key) {
      return this.config[key];
    },
    set : function(key, val) {
      var c;
      key && "undefined" !== typeof val && key in this.config	&& (this.config[key] = val, c = key + "Change", this._evt && c in this._evt.events && this.fire(c));
    }
  };

  function SWFReference(a, b, c) {
    fRegEvents.call(this);
    var d = this._id = fGenerateId("uploader-swf"), c = c || {}, e = ((c.version || sFlashVersion) + "").split("."),
      e = SWFReference.isFlashVersionAtLeast(parseInt(e[0], 10), parseInt(e[1], 10), parseInt(e[2], 10)),
      f = SWFReference.isFlashVersionAtLeast(8, 0, 0) && !e && c.useExpressInstall,
      g = f ? sFlashDownload : b,
      b = "<object ", h = "&SWFId=" + d + "&callback=" + sFlashEventHandler + "&allowedDomain=" + document.location.hostname;
    SWFReference._instances[d] = this;
    if (a && (e || f) && g) {
      b += 'id="' + d + '" ';
      b = Browser.ie ? b + ('classid="' + sIEFlashClassId + '" ') : b
      + ('type="' + sShockwaveFlash + '" data="' + g + '" ');
      b += 'width="100%" height="100%">';
      Browser.ie && (b += '<param name="movie" value="' + g + '"/>');
      for (var j in c.fixedAttributes)
        oa.hasOwnProperty(j)
        && (b += '<param name="' + j + '" value="' + c.fixedAttributes[j] + '"/>');
      for (var s in c.flashVars)
        j = c.flashVars[s], "string" === typeof j
        && (h += "&" + s + "=" + encodeURIComponent(j));
      h && (b += '<param name="flashVars" value="' + h + '"/>');
      a.innerHTML = b + "</object>";
      this.swf = document.getElementById(d);
    } else
      this.publish("wrongflashversion", {fireOnce : !0}), this.fire("wrongflashversion", {type : "wrongflashversion"});
  }

  SWFReference.getFlashVersion = function() {
    return "" + Browser.flashMajor + "." + ("" + Browser.flashMinor) + "." + ("" + Browser.flashRev);
  };
  SWFReference.isFlashVersionAtLeast = function(a, b, c) {return true;
    /*var d = parseInt(Browser.flashMajor, 10), e = parseInt(Browser.flashMinor, 10), f = parseInt(
     Browser.flashRev, 10), a = parseInt(a || 0, 10), b = parseInt(b || 0,
     10), c = parseInt(c || 0, 10);
     return a === d ? b === e ? c <= f : b < e : a < d;*/
  };
  SWFReference._instances = SWFReference._instances || {};
  SWFReference.eventHandler = function(a, b) {SWFReference._instances[a]._eventHandler(b);};
  SWFReference.prototype = {
    initializer : function() {},
    _eventHandler : function(a) {
      "swfReady" === a.type ? (this.publish("swfReady", {fireOnce : !0}), this.fire("swfReady", a))
        : "log" !== a.type && this.fire(a.type, a);
    },
    callSWF : function(a, b) {
      b || (b = []);
      return this.swf[a] ? this.swf[a].apply(this.swf, b) : null;
    },
    toString : function() {return "SWF " + this._id;}
  };
  SWFReference.prototype.constructor = SWFReference;

  function SWFProvider(a) {
    this.swfContainerId = fGenerateId("uploader");
    this.queue = this.swfReference = null;
    this.buttonState = "up";
    this.config = {
      enabled : !0,
      multipleFiles : !0,
      buttonClassNames : {
        hover : "uploader-button-hover",
        active : "uploader-button-active",
        disabled : "uploader-button-disabled",
        focus : "uploader-button-selected"
      },
      containerClassNames : {hover : "uphotBg"},
      fileFilters : aFilters,
      fileFieldName : "FileData",
      simLimit : 1,
      retryCount : 3,
      postVarsPerFile : {},
      swfURL : "./swf/FlashUploader.swf",
      uploadURL : "./fd"
    };
    Parent.apply(this, arguments);
  }
  SWFProvider.prototype = {
    constructor : SWFProvider,
    name : "uploader",
    buttonState : "up",
    swfContainerId : null,
    swfReference : null,
    queue : null,
    initializer : function() {
      this.publish("fileselect");
      this.publish("uploadstart");
      this.publish("fileuploadstart");
      this.publish("uploadprogress");
      this.publish("totaluploadprogress");
      this.publish("uploadcomplete");
      this.publish("alluploadscomplete");
      this.publish("uploaderror");
      this.publish("mouseenter");
      this.publish("mouseleave");
      this.publish("mousedown");
      this.publish("mouseup");
      this.publish("click");
    },
    render : function(a) {
      a && (this.renderUI(a), this.bindUI());
    },
    renderUI : function(a) {
      this.contentBox = a;
      this.contentBox.style.position = "relative";
      var b = fCreateContentEle("<div id='" + this.swfContainerId + "' style='position:absolute;top:0px; left: 0px; margin: 0; padding: 0; border: 0; width:100%; height:100%'></div>");
      b.style.width = a.offsetWidth + "px";
      b.style.height = a.offsetHeight + "px";
      this.contentBox.appendChild(b);
      this.swfReference = new SWFReference(b, this.get("swfURL"), {
        version : "10.0.45",
        fixedAttributes : {
          wmode : "transparent",
          allowScriptAccess : "always",
          allowNetworking : "all",
          scale : "noscale"
        }
      });
    },
    bindUI : function() {
      this.swfReference.on("swfReady", function() {
        this.setMultipleFiles();
        this.setFileFilters();
        this.triggerEnabled();
        this.after("multipleFilesChange", this.setMultipleFiles, this);
        this.after("fileFiltersChange", this.setFileFilters, this);
        this.after("enabledChange", this.triggerEnabled, this);
      }, this);
      this.swfReference.on("fileselect", this.updateFileList, this);
      this.swfReference.on("mouseenter", function() {this.setContainerClass("hover", !0);}, this);
      this.swfReference.on("mouseleave", function() {this.setContainerClass("hover", !1);}, this);
    },
    setContainerClass : function(a, b) {
      b ? fAddClass(this.contentBox, this.get("containerClassNames")[a]) : fRemoveClass(
        this.contentBox, this.get("containerClassNames")[a]);
    },
    setFileFilters : function() {
      this.swfReference && 0 < this.get("fileFilters").length
      && this.swfReference.callSWF("setFileFilters", [this.get("fileFilters")]);
    },
    setMultipleFiles : function() {
      this.swfReference && this.swfReference.callSWF("setAllowMultipleFiles", [this.get("multipleFiles")]);
    },
    triggerEnabled : function() {
      this.get("enabled")
        ? (this.swfReference.callSWF("enable"), this.swfReference.swf.setAttribute("aria-disabled", "false"))
        : (this.swfReference.callSWF("disable"), this.swfReference.swf.setAttribute("aria-disabled", "true"))
    },
    updateFileList : function(a) {
      this.swfReference.swf.focus();
      for (var a = a.fileList, b = [], c = this.swfReference, d = 0; d < a.length; d++) {
        var e = {};
        e.id = a[d].fileId;
        e.name = a[d].fileReference.name;
        e.size = a[d].fileReference.size;
        e.type = a[d].fileReference.type;
        e.dateCreated = a[d].fileReference.creationDate;
        e.dateModified = a[d].fileReference.modificationDate;
        e.uploader = c;
        b.push(new SWFUploader(e));
      }
      0 < b.length && this.fire("fileselect", {fileList : b});
    },
    uploadEventHandler : function(a) {
      switch (a.type) {
        case "executor:uploadstart" :
          this.fire("fileuploadstart", a);
          break;
        case "executor:uploadprogress" :
          this.fire("uploadprogress", a);
          break;
        case "uploaderqueue:totaluploadprogress" :
          this.fire("totaluploadprogress", a);
          break;
        case "executor:uploadcomplete" :
          this.fire("uploadcomplete", a);
          break;
        case "uploaderqueue:alluploadscomplete" :
          this.queue = null;
          this.fire("alluploadscomplete", a);
          break;
        case "executor:uploaderror" :
        case "uploaderqueue:uploaderror" :
          this.fire("uploaderror", a);
          break;
        case "executor:uploadcancel" :
        case "uploaderqueue:uploadcancel" :
          this.fire("uploadcancel", a);
      }
    },
    upload : function(uploader, url, postVars) {
      var url = url || this.get("uploadURL"), postVars = fMergeJson(postVars, this.get("postVarsPerFile")), id = uploader.id,
        postVars = postVars.hasOwnProperty(id) ? postVars[id] : postVars;
      uploader instanceof SWFUploader
      && (uploader.on("uploadstart", this.uploadEventHandler, this),
        uploader.on("uploadprogress", this.uploadEventHandler, this),
        uploader.on("uploadcomplete", this.uploadEventHandler, this),
        uploader.on("uploaderror", this.uploadEventHandler, this),
        uploader.on("uploadcancel", this.uploadEventHandler, this),
        uploader.startUpload(url, postVars, this.get("fileFieldName")));
    }
  };

  function SWFUploader(a) {
    this.bytesSpeed = this.bytesPrevLoaded = 0;
    this.bytesSpeeds = [];
    this.preTime = this.remainTime = 0;
    this.config = {
      id : "",
      name : "",
      size : "",
      type : "",
      dateCreated : "",
      dateModified : "",
      uploader : ""
    };
    Parent.apply(this, arguments);
  }
  SWFUploader.prototype = {
    constructor : SWFUploader,
    name : "executor",
    initializer : function() {
      this.id = fGenerateId("file");
    },
    swfEventHandler : function(a) {
      if (a.id === this.get("id"))
        switch (a.type) {
          case "uploadstart" :
            this.fire("uploadstart", {uploader : this.get("uploader")});
            break;
          case "uploadprogress" :
            var b = (new Date).getTime(), c = (b - this.preTime) / 1E3, d = 0;
            if (1 <= c || 0 == this.bytesPrevLoaded) {
              this.bytesSpeed = Math.round((a.bytesLoaded - this.bytesPrevLoaded) / c);
              this.bytesPrevLoaded = a.bytesLoaded;
              this.preTime = b;
              5 < this.bytesSpeeds.length && this.bytesSpeeds.shift();
              this.bytesSpeeds.push(this.bytesSpeed);
              for (b = 0; b < this.bytesSpeeds.length; b++)
                d += this.bytesSpeeds[b];
              this.bytesSpeed = Math.round(d / this.bytesSpeeds.length);
              this.remainTime = Math.ceil((a.bytesTotal - a.bytesLoaded) / this.bytesSpeed);
            }
            this.fire("uploadprogress", {
              originEvent : a,
              bytesLoaded : a.bytesLoaded,
              bytesSpeed : this.bytesSpeed,
              bytesTotal : a.bytesTotal,
              remainTime : this.remainTime,
              percentLoaded : Math.min(100, Math.round(1E4 * a.bytesLoaded / a.bytesTotal) / 100)
            });
            break;
          case "uploadcomplete" :
            this.fire("uploadfinished", {originEvent : a});
            break;
          case "uploadcompletedata" :
            this.fire("uploadcomplete", {
              originEvent : a,
              data : a.data
            });
            break;
          case "uploadcancel" :
            this.fire("uploadcancel", {originEvent : a});
            break;
          case "uploaderror" :
            this.fire("uploaderror", {
              originEvent : a,
              status : a.status,
              statusText : a.message,
              source : a.source
            });
        }
    },
    startUpload : function(url, postVars, fileFieldName) {
      if (this.get("uploader")) {
        var uploader = this.get("uploader"), fileFieldName = fileFieldName || "FileData", id = this.get("id"), postVars = postVars || null;
        uploader.on("uploadstart", this.swfEventHandler, this);
        uploader.on("uploadprogress", this.swfEventHandler, this);
        uploader.on("uploadcomplete", this.swfEventHandler, this);
        uploader.on("uploadcompletedata", this.swfEventHandler, this);
        uploader.on("uploaderror", this.swfEventHandler, this);
        this.remainTime = this.bytesSpeed = this.bytesPrevLoaded = 0;
        this.bytesSpeeds = [];
        postVars.name = this.get("name");
        postVars.size = this.get("size");
        url=fAddVars(postVars, url);
        if (!this.preTime)
          this.preTime = (new Date).getTime();
        uploader.callSWF("upload", [id, url, postVars, fileFieldName]);
      }
    },
    cancelUpload : function() {
      this.get("uploader")
      && (this.get("uploader").callSWF("cancel", [this.get("id")]), this.fire("uploadcancel"));
    }
  };

  function StreamProvider(a) {
    this.buttonBinding = this.queue = this.fileInputField = null;
    this.config = {
      enabled : !0,
      multipleFiles : !0,
      dragAndDropArea : "",
      dragAndDropTips : "",
      fileFilters : aFilters,
      fileFieldName : "FileData",
      simLimit : 1,
      retryCount : 3,
      postVarsPerFile : {},
      uploadURL : "./upload"
    };
    Parent.apply(this, arguments);
  }
  StreamProvider.prototype = {
    constructor : StreamProvider,
    name : "stream_provider",
    initializer: function(){
      this.publish("fileselect");
      this.publish("uploadstart");
      this.publish("fileuploadstart");
      this.publish("uploadprogress");
      this.publish("totaluploadprogress");
      this.publish("uploadcomplete");
      this.publish("alluploadscomplete");
      this.publish("uploaderror");
      this.publish("dragenter");
      this.publish("dragover");
      this.publish("dragleave");
      this.publish("drop");
    },
    render : function(a) {
      a && (this.renderUI(a), this.bindUI());
    },
    renderUI : function(a) {
      this.contentBox = a;
      this.fileInputField = fCreateContentEle("<input type='file' style='visibility:hidden;width:0px;height:0px;'>");
      this.contentBox.appendChild(this.fileInputField);
      this.get("dragAndDropArea") && !this.get("dragAndDropArea").nodeType && this.set("dragAndDropArea", document.getElementById(this.get("dragAndDropArea")));
      bDraggable && this.get("dragAndDropArea") && (fAddClass(this.get("dragAndDropArea"), 'stream-browse-drag-files-area'), this.get("dragAndDropArea").appendChild(fCreateContentEle(this.get("dragAndDropTips"))));
    },
    bindUI : function() {
      this.bindSelectButton();
      this.setMultipleFiles();
      this.setFileFilters();
      this.bindDropArea();
      this.triggerEnabled();
      this.after("multipleFilesChange", this.setMultipleFiles, this);
      this.after("fileFiltersChange", this.setFileFilters, this);
      this.after("enabledChange", this.triggerEnabled, this);
      this.after("dragAndDropAreaChange", this.bindDropArea, this);
      fAddEventListener(this.fileInputField, "change", fExtend(this.updateFileList, this));
    },
    bindDropArea : function() {
      var a = this.get("dragAndDropArea");
      this.dropBinding = fExtend(this.dragEventHandler, this);
      null !== a	&& (fAddEventListener(a, "drop", this.dropBinding),
        fAddEventListener(a, "dragenter", this.dropBinding),
        fAddEventListener(a, "dragover", this.dropBinding),
        fAddEventListener(a, "dragleave", this.dropBinding));
    },
    dragEventHandler : function(evt) {
      evt = evt || window.event;
      evt.preventDefault ? evt.preventDefault() : evt.returnValue = !1;
      evt.stopPropagation ? evt.stopPropagation() : evt.cancelBubble = !0;
      switch (evt.type) {
        case "dragenter" :
          this.fire("dragenter");
          break;
        case "dragover" :
          this.fire("dragover");
          break;
        case "dragleave" :
          this.fire("dragleave");
          break;
        case "drop" :
          var callback = function(files, self) {
            for (var list = [], c = 0; c < files.length; c++)
              list.push(new StreamUploader(files[c]));
            0 < list.length && self.fire("fileselect", {fileList : list});
          };
          if (bFolder) {
            var items = evt.dataTransfer.items;
            if (items.length && items[items.length - 1]) {
              var entry = items[items.length - 1].webkitGetAsEntry() || items[items.length - 1].getAsEntry();
              entry && this.traverseFileTree(entry.filesystem.root, callback);
            }
          } else {
            var files = evt.dataTransfer.files;
            if (evt.MOZ_SOURCE_MOUSE) {
              for (var list = [], c = 0; c < files.length; c++)
                files[c].size > 0 && list.push(files[c]);
              files = list;
            }
            callback(files, this);
          }
          this.fire("drop");
      }
    },
    traverseFileTree : function (directory, callback) {
      callback.pending || (callback.pending = 0);
      callback.files || (callback.files = []);
      callback.pending++;
      var self = this, relativePath = directory.fullPath.replace(/^\//, "").replace(/(.+?)\/?$/, "$1/"), reader = directory.createReader();
      reader.readEntries(function(entries) {
        callback.pending--;
        if (!entries.length) {
          fShowMessage("\u5FFD\u7565\u7A7A\u6587\u4EF6\u5939\uFF1A`" + relativePath + directory.name + "`", true);
        } else {
          for (var i = 0; i < entries.length; i++) {
            var entry = entries[i];
            if (entry.isFile) {
              callback.pending++;
              entry.file(function(f) {
                f.RelativePath = relativePath + f.name; /** self define argument */
                callback.files.push(f);
                (--callback.pending === 0) && callback(callback.files, self);
              });
              continue;
            }
            self.traverseFileTree(entry, callback);
          }
        }
        (callback.pending === 0) && callback(callback.files, self);
      });
    },
    rebindFileField : function() {
      this.fileInputField.parentNode.removeChild(this.fileInputField);
      this.fileInputField = fCreateContentEle("<input type='file' style='visibility:hidden;width:0px;height:0px;'>");
      this.contentBox.appendChild(this.fileInputField);
      this.get("dragAndDropArea") && !this.get("dragAndDropArea").nodeType && this.set("dragAndDropArea", document.getElementById(this.get("dragAndDropArea")));
      bDraggable && (fAddClass(this.get("dragAndDropArea"), 'stream-browse-drag-files-area'));
      this.setMultipleFiles();
      this.setFileFilters();
      fAddEventListener(this.fileInputField, "change", fExtend(this.updateFileList, this));
    },
    bindSelectButton : function() {
      this.buttonBinding = fExtend(this.openFileSelectDialog, this);
      fAddEventListener(this.contentBox, "click", this.buttonBinding);
    },
    setMultipleFiles : function() {
      !0 === this.get("multipleFiles")
      && this.fileInputField.setAttribute("multiple", "multiple")
    },
    setFileFilters : function() {
      var a = this.get("fileFilters");
      0 < a.length ? this.fileInputField.setAttribute("accept", a
        .join(",")) : this.fileInputField.setAttribute(
        "accept", "")
    },
    triggerEnabled : function() {
      var a = this.get("dragAndDropArea");
      if (this.get("enabled") && null === this.buttonBinding)
        this.bindSelectButton(), this.bindDropArea(), fRemoveClass(a, 'stream-disabled');
      else if (!this.get("enabled") && this.buttonBinding) {
        fRemoveEventListener(this.contentBox, "click", this.buttonBinding),
          this.buttonBinding = null;

        null !== a && this.dropBinding != null && (fRemoveEventListener(a, "drop", this.dropBinding),
          fRemoveEventListener(a, "dragenter", this.dropBinding),
          fRemoveEventListener(a, "dragover", this.dropBinding),
          fRemoveEventListener(a, "dragleave", this.dropBinding),
          fAddClass(a, 'stream-disabled'));
      }
    },
    updateFileList : function(a) {
      for (var a = a.target.files, b = [], c = 0; c < a.length; c++) {
        if (a[c].name == ".") continue;
        b.push(new StreamUploader(a[c]));
      }
      0 < b.length && this.fire("fileselect", {fileList : b});
      this.rebindFileField();
    },
    openFileSelectDialog : function(a) {
      this.fileInputField.click && a.target != this.fileInputField && this.fileInputField.click();
    },
    uploadEventHandler : function(a) {
      switch (a.type) {
        case "executor:uploadstart" :
          this.fire("fileuploadstart", a);
          break;
        case "executor:uploadprogress" :
          this.fire("uploadprogress", a);
          break;
        case "uploaderqueue:totaluploadprogress" :
          this.fire("totaluploadprogress", a);
          break;
        case "executor:uploadcomplete" :
          this.fire("uploadcomplete", a);
          break;
        case "uploaderqueue:alluploadscomplete" :
          this.queue = null;
          this.fire("alluploadscomplete", a);
          break;
        case "executor:uploaderror" :
        case "uploaderqueue:uploaderror" :
          this.fire("uploaderror", a);
          break;
        case "executor:uploadcancel" :
        case "uploaderqueue:uploadcancel" :
          this.fire("uploadcancel", a);
      }
    },
    upload : function(uploader, url, postVars) {
      var url = url || this.get("uploadURL"), postVars = fMergeJson(postVars, this.get("postVarsPerFile")),
        d = uploader.id, postVars = postVars.hasOwnProperty(d) ? postVars[d] : postVars;
      uploader instanceof StreamUploader
      && (uploader.on("uploadstart", this.uploadEventHandler, this),
        uploader.on("uploadprogress", this.uploadEventHandler, this),
        uploader.on("uploadcomplete", this.uploadEventHandler, this),
        uploader.on("uploaderror", this.uploadEventHandler, this),
        uploader.on("uploadcancel", this.uploadEventHandler, this),
        uploader.startUpload(url, postVars, this.get("fileFieldName")));
    }
  };

  var StreamUploader = function(){
    this.remainTime = this.bytesSpeed = this.bytesStart = this.bytesPrevLoaded = 0;
    this.bytesSpeeds = [];
    this.retryTimes = this.preTime = 0;
    this.config = {
      id : "",
      name : "",
      size : "",
      type : "",
      dateCreated : "",
      dateModified : "",
      uploader : "",
      uploadURL : "",
      serverAddress : "",
      portionSize : 10485760,
      parameters : {},
      fileFieldName : "FileData",
      uploadMethod : "formUpload"
    };
    Parent.apply(this, arguments);
  };
  StreamUploader.isValidFile = function(a) {return "undefined" != typeof File && a instanceof File;};
  StreamUploader.canUpload = function() {return "undefined" != typeof FormData;};
  StreamUploader.prototype = {
    constructor : StreamUploader,
    name: "executor",
    initializer: function(file){
      this.XHR = null;
      this.retryTimes = 10;
      this.retriedTimes = 0;
      this.file = null;
      this.fileId = null;
      this.filePiece = 10485760;/** 10M. */
      this.fileSizeValue = 0;
      this.fileStartPosValue = null;

      this.durationTime = 2000;
      this.xhrHandler = null;

      var b = StreamUploader.isValidFile(file) ? file : StreamUploader.isValidFile(file.file)	? file.file	: !1;
      this.get("id") || this.set("id", fGenerateId("file"));
      if (b && StreamUploader.canUpload()) {
        if (!this.file)
          this.file = b;

        this.set("name", b.RelativePath || b.webkitRelativePath || b.name || b.fileName);
        if (this.get("size") != (b.size || b.fileSize))
          this.set("size", b.size || b.fileSize);
        this.get("type") || this.set("type", b.type);
        b.lastModifiedDate && !this.get("dateModified")	&& this.set("dateModified", b.lastModifiedDate);
      }
    },
    resetXhr: function(){
      if(this.XHR){
        try{
          this.XHR.upload.removeEventListener("progress", this.xhrHandler),
            this.XHR.upload.removeEventListener("error", this.xhrHandler),
            this.XHR.upload.removeEventListener("abort", this.xhrHandler),
            this.XHR.removeEventListener("loadend", this.xhrHandler),
            this.XHR.removeEventListener("error", this.xhrHandler),
            this.XHR.removeEventListener("abort", this.xhrHandler),
            this.XHR.removeEventListener("readystatechange", this.xhrHandler);
        }catch(e){throw e;}
        this.XHR = null;
      }
    },
    formUpload : function() {
      this.resetXhr();
      this.XHR = new XMLHttpRequest;
      this.uploadEventHandler = fExtend(this.uploadEventHandler, this);
      var fd = new FormData, fileFileName = this.get("fileFieldName"),
        url = this.get("uploadURL"), _xhr = this.XHR, _upload = _xhr.upload;
      this.set("uploadMethod", "formUpload");
      this.bytesStart = 0;
      this.preTime = (new Date).getTime();
      fd.append(fileFileName, this.file);
      _xhr.addEventListener("loadstart", this.uploadEventHandler, !1);
      _upload.addEventListener("progress", this.uploadEventHandler, !1);
      _xhr.addEventListener("load", this.uploadEventHandler, !1);
      _xhr.addEventListener("error", this.uploadEventHandler, !1);
      _upload.addEventListener("error", this.uploadEventHandler, !1);
      _upload.addEventListener("abort", this.uploadEventHandler, !1);
      _xhr.addEventListener("abort", this.uploadEventHandler, !1);
      _xhr.addEventListener("loadend", this.uploadEventHandler, !1);
      _xhr.addEventListener("readystatechange", this.uploadEventHandler, !1);
      _xhr.open("POST", url, !0);
      _xhr.send(fd);
      this.fire("uploadstart", {xhr : _xhr});
    },
    streamUpload: function(pos){
      /** whether continue uploading. */
      var _url = this.get("uploadURL");
      this.resetXhr();
      this.resume = false;
      this.bytesStart = pos;
      this.XHR = new XMLHttpRequest;
      this.xhrHandler = fExtend(this.uploadEventHandler, this);
      //register callback function
      var _xhr = this.XHR, upload = _xhr.upload;
      _xhr.addEventListener("loadstart", this.xhrHandler, !1);
      upload.addEventListener("progress", this.xhrHandler, !1);
      _xhr.addEventListener("load", this.xhrHandler, !1);
      _xhr.addEventListener("error", this.xhrHandler, !1);
      upload.addEventListener("error", this.xhrHandler, !1);
      upload.addEventListener("abort", this.xhrHandler, !1);
      _xhr.addEventListener("abort", this.xhrHandler, !1);
      _xhr.addEventListener("loadend", this.xhrHandler, !1);
      _xhr.addEventListener("readystatechange", this.xhrHandler, !1);
      var blob = this.sliceFile(this.file, pos, pos + this.filePiece);
      var range = "bytes "+ pos + "-"+ (pos + blob.size-1) + "/" + this.get("size");
      this.preTime = (new Date).getTime();
      _xhr.open("POST", _url, !0);
      _xhr.setRequestHeader("Content-Range", range);
      _xhr.send(blob);
      0 === pos && this.fire("uploadstart", {xhr : _xhr});
    },
    resumeUpload: function() {
      /** when Browse has `File`, but has not `File.slice` */
      if (!bFileSlice) {
        this.formUpload();
        return;
      }

      this.resetXhr();
      this.XHR = new XMLHttpRequest;
      this.resume = true;

      var _url = this.get("uploadURL") + "&" + fGetRandom();
      this.xhrHandler = fExtend(this.uploadEventHandler, this);
      this.XHR.addEventListener("loadstart", this.xhrHandler, !1);
      this.XHR.addEventListener("load", this.xhrHandler, !1);
      this.XHR.addEventListener("abort", this.xhrHandler, !1);
      this.XHR.addEventListener("error", this.xhrHandler, !1);
      this.XHR.addEventListener("loadend", this.xhrHandler, !1);
      this.XHR.addEventListener("readystatechange", this.xhrHandler, !1);
      this.preTime = (new Date).getTime();
      this.XHR.open("GET", _url, !0);
      this.XHR.send(null);
    },
    retry: function(){
      this.retriedTimes++;
      var g = this;
      2 > this.retriedTimes ? this.resumeUpload()
        : (this.timeoutHandler && clearTimeout(this.timeoutHandler), this.timeoutHandler = setTimeout(function() {g.resumeUpload()}, 1E4));
    },
    uploadEventHandler: function(event){
      var xhr = this.XHR, method = this.get("uploadMethod");
      switch(event.type){
        case "load":
          var uploaded = 0;
          var respJson = null;
          var bError = !1;
          try {
            if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 308)) {
              uploaded = (respJson = eval("(" + xhr.responseText + ")")) ? respJson.start : -1;
            } else if (xhr.status < 500 && xhr.status >= 400) {
              bError = !0;
            } else if (xhr.status < 200) {return;}
            /** the response can't process the request, so throws out the error. */
            bError = bError || respJson.success == false;
          } catch(e) {
            bError = "formUpload" === method || this.retriedTimes > this.retryTimes;
            if (!bError) {
              this.retry();
              return;
            }
          }
          if (bError) {
            this.fire("uploaderror", {
              originEvent : event,
              status : xhr.status,
              statusText : xhr.responseText,
              source : respJson && respJson.message
            });
            return;
          }
          //check whether upload complete yet
          if(uploaded < this.get("size") -1) {
            this.retriedTimes = 0;
            /** StreamUploader request is over and mark the date. */
            this.streamUpload(uploaded);
          } else {
            this.fire("uploadcomplete", {originEvent : event, data : event.target.responseText});
          }
          break;
        case "error":
          this.retriedTimes < this.retryTimes ? this.retry()
            : this.fire("uploaderror", {
            originEvent : event,
            status : xhr.status,
            statusText : xhr.statusText,
            source : "io"
          });
          break;
        case "abort":
          this.fire("uploadcancel", {originEvent : event});
          break;
        case "progress":
          var total = this.get("size"), loaded = this.bytesStart + event.loaded,
            now = (new Date).getTime(), cost = (now - this.preTime) / 1E3, totalSpeeds = 0;
          if (0.68 <= cost || 0 === this.bytesSpeeds.length) {
            this.bytesPrevLoaded = Math.max(this.bytesStart, this.bytesPrevLoaded);
            this.bytesSpeed = Math.round((loaded - this.bytesPrevLoaded) / cost);
            this.bytesPrevLoaded = loaded;
            this.preTime = now;
            5 < this.bytesSpeeds.length && this.bytesSpeeds.shift();
            5 > this.bytesSpeeds.length && (this.bytesSpeed = this.bytesSpeed / 2);
            this.bytesSpeeds.push(this.bytesSpeed);
            for (var i = 0; i < this.bytesSpeeds.length; i++)
              totalSpeeds += this.bytesSpeeds[i];
            this.bytesSpeed = Math.round(totalSpeeds / this.bytesSpeeds.length);
            this.remainTime = Math.ceil((total - loaded) / this.bytesSpeed);
          }
          this.fire("uploadprogress", {
            originEvent : event,
            bytesLoaded : loaded,
            bytesTotal : total,
            bytesSpeed : this.bytesSpeed,
            remainTime : this.remainTime,
            percentLoaded : Math.min(100, Math.floor(1E4 * loaded / total) / 100)
          });
          break;
        case "readystatechange":
          this.fire("readystatechange", {readyState : event.target.readyState, originEvent : event});
      }
    },
    startUpload: function(url, postVars, fileFieldName){
      this.fileStartPosValue = null;
      this.retriedTimes = 0;

      postVars.name = this.get("name");
      postVars.size = this.get("size");
      var method = this.get("uploadMethod");
      this.set("uploadURL", fAddVars(postVars, url));
      this.set("parameters", postVars);
      this.set("fileFieldName", fileFieldName);
      this.remainTime = this.bytesSpeed = this.bytesPrevLoaded = 0;
      this.bytesSpeeds = [];
      this.resetXhr();
      switch (method) {
        case "formUpload" :
          this.formUpload();
          break;
        case "streamUpload" :
          this.streamUpload();
          break;
        case "resumeUpload" :
          this.resumeUpload()
      }
    },
    sliceFile: function(f, startPos, endPos){
      startPos = startPos || 0;
      endPos = endPos || 0;
      return f.slice ? f.slice(startPos, endPos) : f.webkitSlice ? f.webkitSlice(startPos, endPos) : f.mozSlice ? f.mozSlice(startPos, endPos) : f;
    },
    cancelUpload : function() {
      this.XHR && (this.XHR.abort(), this.resetXhr());
    }
  };

  function Main(cfg){
    cfg = cfg || {};
    aFilters = fIsArray(cfg.extFilters) ? cfg.extFilters : aFilters;
    this.bStreaming = bStreaming;
    this.bDraggable = bDraggable;
    this.uploadInfo = {};
    this.config = {
      enabled : !0,
      customered : !!cfg.customered,
      multipleFiles : !!cfg.multipleFiles,
      autoRemoveCompleted : !!cfg.autoRemoveCompleted,
      autoUploading : cfg.autoUploading == null ? true : !!cfg.autoUploading,
      dragAndDropArea: cfg.dragAndDropArea,
      dragAndDropTips: cfg.dragAndDropTips || "<span>把文件(文件夹)拖拽到这里</span>",
      fileFieldName : cfg.fileFieldName || "FileData",
      browseFileId : cfg.browseFileId || "i_select_files",
      browseFileBtn : cfg.browseFileBtn || "<div>请选择文件</div>",
      filesQueueId : cfg.filesQueueId || "i_stream_files_queue",
      filesQueueHeight : cfg.filesQueueHeight || 450,
      messagerId : cfg.messagerId || "i_stream_message_container",
      onSelect : cfg.onSelect,
      onAddTask: cfg.onAddTask,
      onMaxSizeExceed : cfg.onMaxSizeExceed,
      onFileCountExceed : cfg.onFileCountExceed,
      onExtNameMismatch : cfg.onExtNameMismatch,
      onCancel : cfg.onCancel,
      onStop : cfg.onStop,
      onCancelAll : cfg.onCancelAll,
      onComplete : cfg.onComplete,
      onQueueComplete: cfg.onQueueComplete,
      onUploadProgress: cfg.onUploadProgress,
      onUploadError: cfg.onUploadError,
      maxSize : cfg.maxSize || 2147483648,
      simLimit : cfg.simLimit || 10000,
      aFilters: aFilters,
      retryCount : cfg.retryCount || 5,
      postVarsPerFile : cfg.postVarsPerFile || {},
      swfURL : cfg.swfURL || "./swf/FlashUploader.swf",
      tokenURL : cfg.tokenURL || "./tk",
      frmUploadURL : cfg.frmUploadURL || Browser.firefox ? "./fd;" + document.cookie : "fd",
      uploadURL : cfg.uploadURL || "./upload"
    };
    Parent.apply(this, arguments);
  }
  Main.applyTo = function(a, b) {
    if (!a || "SWF.eventHandler" != a)
      return null;
    try {
      return SWFReference.eventHandler.apply(SWFReference, b);
    } catch (c) {
      return null;
    }
  };
  Main.prototype = {
    constructor : Main,
    name : "uploader",
    initializer : function() {
      sStreamMessagerId = this.config.messagerId;
      this.startPanel = document.getElementById(this.config.browseFileId);
      /** the default UI */
      if (!this.config.customered) {
        fAddClass(this.startPanel, "stream-browse-files");
        this.startPanel.appendChild(fCreateContentEle(this.config.browseFileBtn));
        var filesQueuePanel = document.getElementById(this.config.filesQueueId);
        fAddClass(filesQueuePanel, "stream-main-upload-box");
        var filesContainerId = fGenerateId("files-container"),
          totalContainerId = fGenerateId("total-container");
        var filesQueue = fCreateContentEle(sFilesContainer.replace("#filesContainerId#", filesContainerId).replace("#filesQueueHeight#", this.config.filesQueueHeight)),
          totalQueue = fCreateContentEle(sTotalContainer.replace("#totalContainerId#", totalContainerId));
        filesQueuePanel.appendChild(filesQueue);
        filesQueuePanel.appendChild(totalQueue);

        this.containerPanel = document.getElementById(filesContainerId);
        this.totalContainerPanel = document.getElementById(totalContainerId);
        this.template = sCellFileTemplate;
      }

      this.fileProvider = new Provider(this.config);
      this.fileProvider.render(this.startPanel);
      this.fileProvider.on("uploadprogress", this.uploadProgress, this);
      this.fileProvider.on("uploadcomplete", this.uploadComplete, this);
      this.fileProvider.on("uploaderror", this.uploadError, this);
      this.fileProvider.on("fileselect", this.fileSelect, this);
      fAddEventListener(window, "beforeunload", fExtend(this.unloadHandler, this));
      this.waiting = [];
      uploading = !1;
      this.totalFileSize = 0;
      this.totalUploadedSize = 0;
    },
    addStreamTask : function(a) {
      var file_id = a.get("id"), cell_file = fCreateContentEle("<li id='" + file_id + "' class='stream-cell-file'></li>");
      cell_file.innerHTML = this.template;
      this.uploadInfo[file_id] = {
        uploadToken : "",
        uploadComplete : !1,
        file : a,
        disabled : !1,
        actived : !1,
        progressNode : this.getNode("stream-process", cell_file),
        cellInfosNode : this.getNode("stream-cell-infos", cell_file)
      };
      this.totalFileSize += this.uploadInfo[file_id].file.get("size");
      if (!this.config.customered) {
        this.getNode("stream-file-name", cell_file).getElementsByTagName("strong")[0].innerHTML = a.get("name");
        this.containerPanel.appendChild(cell_file);
        this.renderUI(file_id);
        this.bindUI(file_id);
      }
      /** do not hidden the upload button */
      /*bStreaming ? this.startPanel.style.display = "none" : (this.startPanel.style.height = "1px", this.startPanel.style.width = "1px");*/
      this.waiting.push(file_id);
      this.config.autoUploading && this.upload(file_id);
    },
    renderUI : function(file_id) {
      var progressNode = this.uploadInfo[file_id].progressNode,
        cellInfosNode = this.uploadInfo[file_id].cellInfosNode,
        size = this.uploadInfo[file_id].file.get("size"),
        total = this.formatBytes(size);
      this.getNode("stream-process-bar", progressNode).innerHTML = "<span style='width:0%;'></span>";
      this.getNode("stream-percent", progressNode).innerHTML = "0%";
      this.getNode("stream-speed", cellInfosNode).innerHTML = "-";
      this.getNode("stream-remain-time", cellInfosNode).innerHTML = "--:--:--";
      this.getNode("stream-uploaded", cellInfosNode).innerHTML = "0/" + total;
      var _total = this.formatBytes(this.totalFileSize);
      this.getNode("_stream-total-size", this.totalContainerPanel).innerHTML = _total;
    },
    bindUI : function(file_id) {
      var b = this.uploadInfo[file_id].progressNode, cancelBtn = this.getNode("stream-cancel", b);
      this.cancelBtnHandler = fExtend(this.cancelUploadHandler, this, {type : "click",	nodeId : file_id});
      fAddEventListener(cancelBtn, "click", this.cancelBtnHandler);
    },
    completeUpload : function(info) {
      this.get("onComplete") ? this.get("onComplete").call(this, info) : this.onComplete(info);
      this.waiting.length == 0 && (this.get("onQueueComplete") ? this.get("onQueueComplete")(info.msg) : this.onQueueComplete(info.msg));
      this.config.autoRemoveCompleted && (info = document.getElementById(info.id), info.parentNode && info.parentNode.removeChild(info));
      uploading = !1;
      this.upload();
    },
    onSelect : function(list) {
      fShowMessage("selected files: " + list.length);
    },
    onFileCountExceed : function(selected, limit) {
      fShowMessage("File counts:" + selected + ", but limited:" + limit, true);
    },
    onMaxSizeExceed : function(file) {
      fShowMessage("File:" + file.name + " size is:" + file.size +" Exceed limited:" + file.limitSize, true);
    },
    onExtNameMismatch: function(file) {
      fShowMessage("Allow ext name: [" + file.filters.toString() + "], not for " + file.name, true);
    },
    onAddTask: function(file) {
      fShowMessage("Add to task << name: [" + file.name);
    },
    onCancel : function(file) {
      fShowMessage("Canceled: " + file.name);
    },
    onStop : function() {
      fShowMessage("Stopped!");
    },
    onCancelAll : function(numbers) {
      fShowMessage(numbers + " files Canceled! ");
    },
    onComplete : function(file) {
      fShowMessage("File:" + file.name + ", Size:" + file.size + " onComplete	[OK]");
    },
    onQueueComplete : function(msg) {
      fShowMessage("onQueueComplete(msg: "+msg+")	---==>		[OK]");
    },
    onUploadError : function(status, msg) {
      fShowMessage("Error Occur.  Status:" + status + ", Message: " + msg, true);
    },
    disable : function() {
      this.fileProvider.set("enabled", !1), this.fileProvider.triggerEnabled(), fAddClass(this.startPanel.children[0], "stream-disable-browser"), fAddClass(this.startPanel, "disabled");
    },
    enable : function() {
      this.fileProvider.set("enabled", !0), this.fileProvider.triggerEnabled(), fRemoveClass(this.startPanel.children[0], "stream-disable-browser"), fRemoveClass(this.startPanel, "disabled");
    },
    stop : function() {
      if (!uploading) return false;
      uploading = !1;
      var files = this.uploadInfo, number = 0;
      /** cancel the unfinished uploading files */
      for(var fileId in files) {
        /** add the `file_id` to `waiting` @ index of 0 */
        if (!files[fileId].uploadComplete) {
          this.cancelOne(fileId, true) && this.uploadInfo[fileId] && this.waiting.unshift(fileId);
          break;
        }
      }
      this.get("onStop") ? this.get("onStop")() : this.onStop();
    },
    cancel : function() {
      uploading = !1;
      var files = this.uploadInfo, number = 0;
      /** cancel the unfinished uploading files */
      for(var fileId in files)
        !files[fileId].uploadComplete && (++number) && this.cancelOne(fileId);
      this.get("onCancelAll") ? this.get("onCancelAll")(number) : this.onCancelAll(number);
    },
    cancelOne : function(file_id, stopping) {
      var provider = this.uploadInfo[file_id].file, actived = this.uploadInfo[file_id].actived;
      provider && provider.cancelUpload && provider.cancelUpload();
      if (!!stopping) return true;

      var totalSize = this.totalFileSize - this.uploadInfo[file_id].file.config.size, info = {
        id:   file_id,
        name: this.uploadInfo[file_id].file.config.name,
        size: this.uploadInfo[file_id].file.config.size,
        totalSize: totalSize,
        formatTotalSize: this.formatBytes(totalSize),
        totalLoaded: this.totalUploadedSize,
        formatTotalLoaded: this.formatBytes(this.totalUploadedSize),
        totalPercent: totalSize == 0 ? 0 : this.totalUploadedSize * 10000 / totalSize / 100
      };
      100 > info.totalPercent && (info.totalPercent = parseFloat(info.totalPercent).toFixed(2));

      this.get("onCancel") ? this.get("onCancel")(info) : this.onCancel(info);
      this.uploadInfo[file_id] && delete this.uploadInfo[file_id];
      fRemoveEventListener(document, "click", this.cancelBtnHandler);
      !this.config.customered && this.containerPanel.removeChild(document.getElementById(file_id));
      if (actived) {
        uploading = !1;
        this.upload();
      } else {
        for(var i in this.waiting)
          if (this.waiting[i] === file_id)
            this.waiting.splice(i, 1);
      }
      var size = provider.config.size;
      this.totalFileSize -= size;
      var _loaded = this.formatBytes(this.totalUploadedSize);
      var percent = this.totalUploadedSize * 10000 / this.totalFileSize / 100;
      100 > percent && (percent = parseFloat(percent).toFixed(2));
      if (this.totalFileSize === 0)
        percent = 100;

      if (!this.config.customered) {
        var _total = this.formatBytes(this.totalFileSize);
        this.getNode("_stream-total-size", this.totalContainerPanel).innerHTML = _total;
        this.getNode("_stream-total-uploaded", this.totalContainerPanel).innerHTML = _loaded;
        this.getNode("stream-percent", this.totalContainerPanel).innerHTML = percent + "%";
        this.getNode("stream-process-bar", this.totalContainerPanel).innerHTML = '<span style="width: '+percent+'%;"></span>';

        /*** TODO: this code will be removed in the future.
         bStreaming ? this.startPanel.style.display = "block"
         : (this.startPanel.style.height = "auto", this.startPanel.style.width = "970px");*/
      }
    },
    cancelUploadHandler : function(event, b) {
      var c = event || window.event, id = b.nodeId, self = this;
      this.preventDefault(c);
      this.stopPropagation(c);
      if (this.uploadInfo[id].disabled)
        return !1;
      this.uploadInfo[id] && !this.uploadInfo[id].uploadComplete;
      this.cancelOne(id);
    },
    unloadHandler : function(evt) {
      var evt = evt || window.event;
      if (this.waiting.length > 0)
        return evt.returnValue = "\u60A8\u6B63\u5728\u4E0A\u4F20\u6587\u4EF6\uFF0C\u5173\u95ED\u6B64\u9875\u9762\u5C06\u4F1A\u4E2D\u65AD\u4E0A\u4F20\uFF0C\u5EFA\u8BAE\u60A8\u7B49\u5F85\u4E0A\u4F20\u5B8C\u6210\u540E\u518D\u5173\u95ED\u6B64\u9875\u9762";
    },
    upload : function(index) {
      if(uploading) return;
      index = this.waiting.shift();
      if(index == null) return;
      uploading = !0;

      this.uploadInfo[index].actived = !0;
      var file = this.uploadInfo[index].file, self = this;
      var frmUploadURL = this.get("frmUploadURL");
      var uploadURL = this.get("uploadURL");

      // 修改为本地获取文件md5
       if(Browser.ie!=9) {

            FileMD5(file.file, {debug: false})
                .then(function (token) {
                    console.log('FileMD5'+new Date())
                    bStreaming && bFileSlice ? (self.uploadFile(file, uploadURL, token, "resumeUpload"))
                        : self.uploadFile(file, frmUploadURL, token, "formUpload");
                })
                ['catch'](function (e) {
                console.error(e);
            });
       }else{
           /*if(server != null && server != "") {
               frmUploadURL = server + frmUploadURL;
               uploadURL = server + uploadURL;
           }*/
           bStreaming && bFileSlice ? (self.uploadFile(file, uploadURL, "testId", "resumeUpload"))
               : self.uploadFile(file, frmUploadURL, "testId", "formUpload");
/*
           var xhr = new XMLHttpRequest;

           var vars = {
               name:	 file.get('name'),
               type: file.get('type'),
               size: file.get('size'),
               modified: file.get("dateModified") + ""
           };
           var tokenUrl = fAddVars(vars, this.get("tokenURL")) + "&" + fGetRandom();
           xhr.open("GET", tokenUrl, !0);
           /!** IE7,8 兼容*!/
           xhr.onreadystatechange = function() {
               if (xhr.readyState != 4 || xhr.status < 200)
                   return false;

               var token, server;
               try {
                   try {
                       token = eval("(" + xhr.responseText + ")").token;
                       server = eval("(" + xhr.responseText + ")").server;
                   } catch(e) {}
                   if (token) {
                       if(server != null && server != "") {
                           frmUploadURL = server + frmUploadURL;
                           uploadURL = server + uploadURL;
                       }
                       bStreaming && bFileSlice ? (self.uploadInfo[index].serverAddress = server,self.uploadFile(file, uploadURL, token, "resumeUpload")) : self.uploadFile(file, frmUploadURL, token, "formUpload");
                   } else {
                       /!** not found any token *!/
                       self.cancelOne(index);
                       var msg = "\u521B\u5EFA\u4E0A\u4F20\u4EFB\u52A1\u5931\u8D25[tokenURL=" + self.get("tokenURL") + "],\u72B6\u6001\u7801:" + xhr.status;
                       fShowMessage(msg, true);
                   }
               } catch(e) {
                   /!** streaming, swf, resume methods all failed, no more try  *!/
               }
           }
           xhr.onerror = function() {
               self.cancelOne(index);
               var msg = "\u521B\u5EFA\u4E0A\u4F20\u4EFB\u52A1\u5931\u8D25,\u72B6\u6001\u7801:" + xhr.status + ",\u8BF7\u68C0\u6D4B\u7F51\u7EDC...";
               fShowMessage(msg, true);
           };
           xhr.send();*/
       }
    },
    uploadFile : function(file, url, token, method) {
      var token = {
        token : token,
        client : method == "formUpload" ? "form" : "html5"
      };
      url = url || "";
      method && file instanceof StreamUploader && file.set("uploadMethod", method);
      this.fileProvider.upload(file, url, token);
    },
    uploadProgress : function(a) {
      var id = a.target.get("id"), percent = Math.min(99.99, a.percentLoaded),
        totalPercent = (this.totalUploadedSize + a.bytesLoaded) * 10000 / this.totalFileSize / 100, totalPercent = Math.min(99.99, totalPercent);
      100 > totalPercent && (totalPercent = parseFloat(totalPercent).toFixed(2));

      if (!this.uploadInfo[id]) return false;
      if (this.config.customered) {
        var info = {
          id:                 id,
          loaded:             a.bytesLoaded,
          formatLoaded:       this.formatBytes(a.bytesLoaded),
          speed:              a.bytesSpeed,
          formatSpeed:        this.formatSpeed(a.bytesSpeed),
          size:               a.bytesTotal,
          formatSize:         this.formatBytes(a.bytesTotal),
          percent:            percent,
          timeLeft:           a.remainTime,
          formatTimeLeft:     this.formatTime(a.remainTime),
          totalSize:          this.totalFileSize,
          formatTotalSize:    this.formatBytes(this.totalFileSize),
          totalLoaded:        this.totalUploadedSize + a.bytesLoaded,
          formatTotalLoaded:  this.formatBytes(this.totalUploadedSize + a.bytesLoaded),
          totalPercent:       totalPercent
        };
        this.get("onUploadProgress") && this.get("onUploadProgress")(info);
        return false;
      }

      var progressNode = this.uploadInfo[id].progressNode,
        cellInfosNode = this.uploadInfo[id].cellInfosNode, bytesLoaded = a.bytesLoaded,
        c = this.formatSpeed(a.bytesSpeed), loaded = this.formatBytes(bytesLoaded),
        total = this.formatBytes(a.bytesTotal), _remainTime = this.formatTime(a.remainTime),
        a = Math.min(99.99, a.percentLoaded);
      100 > a && (a = parseFloat(a).toFixed(2));
      this.getNode("stream-process-bar", progressNode).innerHTML = "<span style='width:"+a+"%;'></span>";
      this.getNode("stream-percent", progressNode).innerHTML = a + "%";
      this.getNode("stream-speed", cellInfosNode).innerHTML = c;
      if (_remainTime)
        this.getNode("stream-remain-time", cellInfosNode).innerHTML = _remainTime;
      this.getNode("stream-uploaded", cellInfosNode).innerHTML = loaded + "/" + total;

      var _loaded = this.formatBytes(this.totalUploadedSize + bytesLoaded);
      var percent = (this.totalUploadedSize + bytesLoaded) * 10000 / this.totalFileSize / 100, percent = Math.min(99.99, percent);
      100 > percent && (percent = parseFloat(percent).toFixed(2));
      this.getNode("_stream-total-uploaded", this.totalContainerPanel).innerHTML = _loaded;
      this.getNode("stream-percent", this.totalContainerPanel).innerHTML = percent + "%";
      this.getNode("stream-process-bar", this.totalContainerPanel).innerHTML = '<span style="width: '+percent+'%;"></span>';
    },
    uploadComplete : function(a) {
      this.totalUploadedSize += a.target.get("size");
      var id = a.target.get("id"), percent = Math.min(100, a.percentLoaded),
        totalPercent = this.totalUploadedSize * 10000 / this.totalFileSize / 100;
      100 > totalPercent && (totalPercent = parseFloat(totalPercent).toFixed(2));
      if (this.totalFileSize === 0)
        percent = 100;

      if (!this.uploadInfo[id]) return false;

      var info = {
        id:                 id,
        name:               a.target.get("name"),
        loaded:             a.target.get("size"),
        formatLoaded:       this.formatBytes(a.target.get("size")),
        size:               a.target.get("size"),
        formatSize:         this.formatBytes(a.target.get("size")),
        percent:            100,
        totalSize:          this.totalFileSize,
        formatTotalSize:    this.formatBytes(this.totalFileSize),
        totalLoaded:        this.totalUploadedSize,
        formatTotalLoaded:  this.formatBytes(this.totalUploadedSize),
        totalPercent:       totalPercent,
        msg:                a.data
      };
      /** uploaded flag and its callback function. */
      this.uploadInfo[id].uploadComplete = !0;

      if (!this.config.customered) {
        var progressNode = this.uploadInfo[id].progressNode,
          cellInfosNode = this.uploadInfo[id].cellInfosNode,
          size = a.target.get("size"), a = eval("(" + a.data + ")"), fmtSize = this.formatBytes(size);
        this.getNode("stream-process-bar", progressNode).innerHTML = "<span style='width:100%;'></span>";
        this.getNode("stream-percent", progressNode).innerHTML = "100%";
        this.getNode("stream-uploaded", cellInfosNode).innerHTML = fmtSize + "/" + fmtSize;
        this.getNode("stream-remain-time", cellInfosNode).innerHTML = "00:00:00";
        this.getNode("stream-cancel", progressNode).innerHTML = "";

        var _loaded = this.formatBytes(this.totalUploadedSize);
        var percent = this.totalUploadedSize * 10000 / this.totalFileSize / 100;
        100 > percent && (percent = parseFloat(percent).toFixed(2));
        if (this.totalFileSize === 0)
          percent = 100;
        this.getNode("_stream-total-uploaded", this.totalContainerPanel).innerHTML = _loaded;
        this.getNode("stream-percent", this.totalContainerPanel).innerHTML = percent + "%";
        this.getNode("stream-process-bar", this.totalContainerPanel).innerHTML = '<span style="width: '+percent+'%;"></span>';
      }

      this.completeUpload(info);
    },
    getNode : function(a, b) {
      return fContains(b || this.containerPanel, a)[0] || null;
    },
    uploadError : function(evt) {
      this.get("onUploadError") ? this.get("onUploadError")(evt.status, evt.statusText) : this.onUploadError(evt.status, evt.statusText);
    },
    fileSelect : function(a) {
      var a = a.fileList, b = 0, c, files = [];
      for (c = 0; c < a.length; c++)
        files.push(a[c].config);
      this.get("onSelect") ? this.get("onSelect")(files) : this.onSelect(files);
      for (c in this.uploadInfo)
        b++;
      if (b == this.get("simLimit") || a.length > this.get("simLimit")) {
        this.get("onFileCountExceed") ? this.get("onFileCountExceed")(Math.max(a.length, b), this.get("simLimit"))
          : this.onFileCountExceed(Math.max(a.length, b), this.get("simLimit"));
        return !1;
      }
      for (c = 0; c < a.length; c++)
        this.validateFile(a[c]) && this.addStreamTask(a[c]);
    },
    validateFile : function(uploader) {
      var name = uploader.get("name"), size = uploader.get("size"),
        ext = -1 !== name.indexOf(".") ? name.replace(/.*[.]/, "").toLowerCase() : "",
        filters = aFilters, valid = !1, msg = "",
        info = {
          id:               uploader.get("id"),
          name:             uploader.get("name"),
          size:             uploader.get("size"),
          formatSize:       this.formatBytes(uploader.get("size")),
          lastModifiedDate: uploader.get("lastModifiedDate"),
          limitSize:        this.get("maxSize"),
          formatLimitSize:  this.formatBytes(this.get("maxSize")),
          filters:          filters
        };
      if(!bStreaming && size > 2147483648){this.uploadError({status:100, statusText:"Flash最大只能上传2G的文件!"});return !1;}
      if (this.get("maxSize") < size)
        this.get("onMaxSizeExceed") ? this.get("onMaxSizeExceed")(info) : this.onMaxSizeExceed(info);
      else {
        filters.length || (valid = !0);
        for (var i = 0; i < filters.length; i++)
          filters[i].toLowerCase() == "." + ext && (valid = !0);
        if (!valid)
          this.get("onExtNameMismatch") ? this.get("onExtNameMismatch")(info) : this.onExtNameMismatch(info);
      }
      valid && this.config.customered && this.get("onAddTask")(info) && this.get("onAddTask")(info);
      return valid;
    },
    formatSpeed : function(a) {
      var b = 0;
      1024 <= Math.round(a / 1024)
        ? (b = Math.round(100 * (a / 1048576)) / 100, b = Math.max(0, b), b = isNaN(b) ? 0 : parseFloat(b).toFixed(2), a = b + "MB/s")
        : (b = Math.round(100 * (a / 1024))	/ 100, b = Math.max(0, b), b = isNaN(b) ? 0 : parseFloat(b).toFixed(2), a = b + "KB/s");
      return a;
    },
    formatBytes : function(size) {
      if (size < 100) {
        return (size + 'B');
      } else if (size < 102400) {
        size = Math.round(100 * (size / 1024)) / 100;
        size = isNaN(size) ? 0 : parseFloat(size).toFixed(2);
        return (size + 'K');
      } else if (size < 1047527424) {
        size = Math.round(100 * (size / 1048576)) / 100;
        size = isNaN(size) ? 0 : parseFloat(size).toFixed(2);
        return (size + 'M');
      }

      size = Math.round(100 * (size / 1073741824)) / 100;
      size = isNaN(size) ? 0 : parseFloat(size).toFixed(2);
      return (size + 'G');
    },
    formatTime : function(time) {
      var total = time || 0, hour = Math.floor(total / 3600), minute = Math.floor((total - 3600 * hour) / 60),
        second = Math.floor(total - 3600 * hour - 60 * minute), hour = "" + (!isNaN(hour) && 0 < hour ? (hour < 10 ? ("0" + hour + ":") : (hour + ":")): "00:"),
        hour = hour + (!isNaN(minute) && 0 < minute ? (minute < 10 ? ("0" + minute + ":") : minute + ":") : "00:");
      return hour += !isNaN(second) && 0 < second ? (second < 10 ? ("0" + second + "") : second): "00";
    },
    preventDefault : function(a) {
      a.preventDefault ? a.preventDefault() : a.returnValue = !1
    },
    stopPropagation : function(a) {
      a.stopPropagation ? a.stopPropagation() : a.cancelBubble = !0
    }
  };

  var sIEFlashClassId = "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000",
    sShockwaveFlash = "application/x-shockwave-flash", sFlashVersion = "10.0.22",
    sFlashDownload = "http://fpdownload.macromedia.com/pub/flashplayer/update/current/swf/autoUpdater.swf?"	+ Math.random(),
    sFlashEventHandler = "SWF.eventHandler",
    oa = {
      align : "",
      allowFullScreen : "",
      allowNetworking : "",
      allowScriptAccess : "",
      base : "",
      bgcolor : "",
      loop : "",
      menu : "",
      name : "",
      play : "",
      quality : "",
      salign : "",
      scale : "",
      tabindex : "",
      wmode : ""
    };
  var Browser = function(a) {
    var b = function(a) {
      var b = 0;
      return parseFloat(a.replace(/\./g, function() {
        return 1 == b++ ? "" : ".";
      }))
    }, c = window, d = c && c.navigator, e = {
      ie : 0,
      opera : 0,
      gecko : 0,
      webkit : 0,
      safari : 0,
      chrome : 0,
      firefox : 0,
      mobile : null,
      air : 0,
      phantomjs : 0,
      air : 0,
      ipad : 0,
      iphone : 0,
      ipod : 0,
      ios : null,
      android : 0,
      silk : 0,
      accel : !1,
      webos : 0,
      caja : d && d.cajaVersion,
      secure : !1,
      os : null,
      nodejs : 0
    }, a = a || d && d.userAgent, d = (c = c && c.location) && c.href, c = 0, f, g, h;
    e.userAgent = a;
    e.secure = d && 0 === d.toLowerCase().indexOf("https");
    if (a) {
      if (/windows|win32/i.test(a))
        e.os = "windows";
      else if (/macintosh|mac_powerpc/i.test(a))
        e.os = "macintosh";
      else if (/android/i.test(a))
        e.os = "android";
      else if (/symbos/i.test(a))
        e.os = "symbos";
      else if (/linux/i.test(a))
        e.os = "linux";
      else if (/rhino/i.test(a))
        e.os = "rhino";
      if (/KHTML/.test(a))
        e.webkit = 1;
      if (/IEMobile|XBLWP7/.test(a))
        e.mobile = "windows";
      if (/Fennec/.test(a))
        e.mobile = "gecko";
      if ((d = a.match(/AppleWebKit\/([^\s]*)/)) && d[1]) {
        e.webkit = b(d[1]);
        if ((d = a.match(/Version\/([^\s]*)/)) && d[1])
          e.safari = d[1];
        if (/PhantomJS/.test(a) && (d = a.match(/PhantomJS\/([^\s]*)/))
          && d[1])
          e.phantomjs = b(d[1]);
        if (/Mobile\//.test(a) || /iPad|iPod|iPhone/.test(a)) {
          if (e.mobile = "Apple", (d = a.match(/OS ([^\s]*)/))
            && d[1] && (d = b(d[1].replace("_", "."))), e.ios = d, e.os = "ios", e.ipad = e.ipod = e.iphone = 0, (d = a
              .match(/iPad|iPod|iPhone/))
            && d[0])
            e[d[0].toLowerCase()] = e.ios;
        } else {
          if (d = a.match(/NokiaN[^\/]*|webOS\/\d\.\d/))
            e.mobile = d[0];
          if (/webOS/.test(a)
            && (e.mobile = "WebOS", (d = a
              .match(/webOS\/([^\s]*);/))
            && d[1]))
            e.webos = b(d[1]);
          if (/ Android/.test(a)) {
            if (/Mobile/.test(a))
              e.mobile = "Android";
            if ((d = a.match(/Android ([^\s]*);/)) && d[1])
              e.android = b(d[1]);
          }
          if (/Silk/.test(a)) {
            if ((d = a.match(/Silk\/([^\s]*)\)/)) && d[1])
              e.silk = b(d[1]);
            if (!e.android)
              e.android = 2.34, e.os = "Android";
            if (/Accelerated=true/.test(a))
              e.accel = !0;
          }
        }
        if ((d = a.match(/(Chrome|CrMo|CriOS)\/([^\s]*)/)) && d[1]
          && d[2]) {
          if (e.chrome = b(d[2]), e.safari = 0, "CrMo" === d[1])
            e.mobile = "chrome";
        } else if (d = a.match(/AdobeAIR\/([^\s]*)/))
          e.air = d[0];
      }
      if (!e.webkit)
        if (/Opera/.test(a)) {
          if ((d = a.match(/Opera[\s\/]([^\s]*)/)) && d[1])
            e.opera = b(d[1]);
          if ((d = a.match(/Version\/([^\s]*)/)) && d[1])
            e.opera = b(d[1]);
          if (/Opera Mobi/.test(a) && (e.mobile = "opera", (d = a.replace("Opera Mobi", "").match(/Opera ([^\s]*)/)) && d[1]))
            e.opera = b(d[1]);
          if (d = a.match(/Opera Mini[^;]*/))
            e.mobile = d[0];
        } else if ((d = a.match(/MSIE\s([^;]*)/)) && d[1])
          e.ie = b(d[1]);
        else if (d = a.match(/Gecko\/([^\s]*)/)) {
          if (e.gecko = 1, (d = a.match(/rv:([^\s\)]*)/)) && d[1])
            e.gecko = b(d[1]);
          if ((d = a.match(/(Firefox)\/([^\s]*)/)) && d[1] && d[2])
            e.firefox = d[2];
        }
    }
    if (e.gecko || e.webkit || e.opera) {
      if (b = navigator.mimeTypes["application/x-shockwave-flash"])
        if (b = b.enabledPlugin)
          f = b.description.replace(/\s[rd]/g, ".").replace(
            /[A-Za-z\s]+/g, "").split(".");
    } else if (e.ie) {
      try {
        g = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"), g.AllowScriptAccess = "always";
      } catch (j) {null !== g && (c = 6);}
      if (0 === c)
        try {
          h = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"),
            f = h.GetVariable("$version").replace(/[A-Za-z\s]+/g, "").split(",");
        } catch (s) {}
    }
    if (fIsArray(f)) {
      if (fIsNumber(parseInt(f[0], 10)))
        e.flashMajor = f[0];
      if (fIsNumber(parseInt(f[1], 10)))
        e.flashMinor = f[1];
      if (fIsNumber(parseInt(f[2], 10)))
        e.flashRev = f[2];
    }
    return e;
  }();
  var bFileSlice = !1;
  var bStreaming = function() {
    var bFile = !1, bHtml5 = !1, bFormData = window.FormData ? !0 : !1, bStreaming = !1;
    "undefined" != typeof File && "undefined" != typeof (new XMLHttpRequest).upload && (bFile = !0);
    if (bFile && (bFileSlice = "slice" in File.prototype || "mozSlice" in File.prototype || "webkitSlice" in File.prototype))
      bHtml5 = !0;
    (function() {
      for (var a = 0; a < aOtherBrowsers.length; a++)
        -1 !== navigator.userAgent.indexOf(aOtherBrowsers[a]) && (bHtml5 = !1);
    })();
    /** some browsers has problems. */
    (bFormData && Browser.os === "windows" && Browser.safari === "5.1.7") && (bFormData = !1);
    return bFile && (bFormData || bHtml5);
  }(), bDraggable = bStreaming && ('draggable' in document.createElement('span')), bFolder = bDraggable && (window.webkitRequestFileSystem || window.requestFileSystem);
  Provider = bStreaming ? StreamProvider : SWFProvider;
  window.Uploader = window.Stream = Main; /** window.Uploader是SWF组件的关键字(保留) */
  window.onbeforeunload = function() {  if (uploading) return "正在上传文件。";  }
})();
